<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        body {
            width: 100vw;
            height: 100vh;
            display: flex;
        }

        .chart {
            margin: auto;
        }
    </style>
</head>

<body>
    <script src="https://d3js.org/d3.v5.min.js"></script>
    <script src="https://d3js.org/d3-force.v1.min.js"></script>
    <script src="./mock/demo06.js"></script>
    <script>
        // https://blog.csdn.net/juzipidemimi/article/details/100787059
        const width = window.innerWidth
        const height = window.innerHeight
        const root = d3.hierarchy(data)
        const nodes = root.descendants()
        const links = root.links()

        const svg = d3.select('body')
            .append('svg')
            .attr('width', width)
            .attr('height', height)
            .attr('class', 'chart')

        const simulation = d3.forceSimulation(nodes)
            .force('charge', d3.forceManyBody())
            .force('link', d3.forceLink(links))
            .force('x', d3.forceX(width / 2))
            .force('y', d3.forceY(height / 2))
    
        simulation.alphaDecay(0.05) 
        simulation.force('charge')
            .strength(-50)
        simulation.force('link')
            .id(d => d.id) // set id getter
            .distance(0) // 连接距离，就是边的长度，但是这是一个近似值，设置为10不一定有10px
            .strength(1) // 连接强度
            .iterations(1) // 迭代次数，每次tick中模拟连接力的次数

        const simulationLinks = svg.append('g')
            .selectAll('line')
            .data(links)
            .enter()
            .append('line')
            .attr('stroke', d => '#c2c2c2')

        const simulationNodes = svg.append('g')
            .attr('fill', '#fff')
            .attr('stroke', '#000')
            .attr('stroke-width', 1.5)
            .selectAll('circle')
            .data(nodes)
            .enter()
            .append('circle')
            .attr('r', 3.5)
            .attr('fill', d => d.children ? null : '#000') // 叶子节点黑底白边，父节点白底黑边
            .attr('stroke', d => d.children ? null : '#fff')
            .call(d3.drag()
                .on('start', started)
                .on('drag', dragged)
                .on('end', ended)
            )
       
        function started(d) {
            if (!d3.event.active) {
                simulation.alphaTarget(.2).restart()
            }
            d.fx = d.x // fx fy 表示节点一下次节点被固定的位置
            d.fy = d.y
        }

        function dragged(d) {
            d.fx = d3.event.x
            d.fy = d3.event.y
        }

        function ended(d) {
            if (!d3.event.active) {
                simulation.alphaTarget(0)
            }
            d.fx = null
            d.fy = null
        }

        simulation.on('tick', ticked) 

        function ticked() {
            simulationLinks.attr('x1', d => d.source.x )
                .attr('y1', d => d.source.y )
                .attr('x2', d => d.target.x )
                .attr('y2', d => d.target.y )

            simulationNodes.attr('cx', d => d.x )
                .attr('cy', d => d.y )
        }
    </script>
</body>

</html>